package org.microboot.data.processor;

import org.microboot.core.constant.Constant;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * @author 胡鹏
 * 默认事务管理器处理器
 */
public class DefaultTransactionManagerPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        /*
            获取SpringBoot自动装配的事务管理器的BeanDefinition，主要是将其primary属性设置为true
                1、如果不开启XA模式，那么是DataSourceTransactionManagerAutoConfiguration创建事务管理器
                2、如果开启了XA模式，那么是AtomikosJtaConfiguration创建事务管理器
            查看BeanDefinition中的beanName就知道了

            注意：
                ① 如果不引入microboot-framework-data-xa包
                    SpringBoot会创建名为transactionManager的DataSourceTransactionManager事务管理器
                    这个事务管理器针对的是JdbcTemplate
                ② 如果引入了microboot-framework-data-xa包【依赖spring-boot-starter-jta-atomikos】
                    SpringBoot会创建名为transactionManager的JtaTransactionManager事务管理器
                    这个事务管理器针对分布式事务，此时必须开启分布式事务【即：getEnableXA()必须返回true】
            问题：当开启分布式事务时，slaves数据源和others数据源在microboot-framework-data-xa中被AtomikosDataSourceBean包装
                 但是这些AtomikosDataSourceBean对象并没有直接交由Spring进行管理，也没有set或add到JtaTransactionManager中
                 那么JtaTransactionManager是怎么实现分布式事务提交的呢？
            解释：跟踪源码发现，在JdbcTemplate准备执行Sql前，先获取Connection连接对象，在此过程中会注册AtomikosDataSourceBean
            流程：execute(...) -> DataSourceUtils.getConnection(obtainDataSource()) -> doGetConnection(dataSource)
                 -> TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(holderToUse, dataSource))
                 obtainDataSource()：拿到每个JdbcTemplate绑定的AtomikosDataSourceBean
                 registerSynchronization()：将AtomikosDataSourceBean注册到了ThreadLocal
                 当提交事务时，会遍历ThreadLocal中的AtomikosDataSourceBean，然后进行提交或回滚
         */
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition(Constant.TRANSACTION_MANAGER_PREFIX);
        if (beanDefinition == null) {
            return;
        }
        //设置为默认事务
        beanDefinition.setPrimary(true);
    }
}
